package org.pi.common.snippets

import scala.Numeric._
import org.pi.common.time.Api._

final class Matrix[@specialized("Float,Int,Double,Boolean") T]
//final class Matrix[T]
    (paramSize: Int*)
    (implicit numeric: Fractional[T], mf:Manifest[T]) 
{
	val size = paramSize.toList
	val length = size.foldLeft(1)(_*_) 
	val data = new Array[T](length)
	val multidimIndices = new org.pi.common.matrix.indices.DefaultMultidimensionalIndices(size)

	@inline
	final def apply(d1: Int) : T = data(d1)
/*	@inline
	final def apply(d1: Int, d2: Int) : T = data(multidimIndices(d1,d2))
	@inline
	final def apply(d1: Int, d2: Int, d3: Int) : T = data(multidimIndices(d1,d2,d3))
*/
	@inline
	final def update(d1: Int, value: T) = { data(d1) = value }
/*	@inline
	final def update(d1: Int, d2: Int, value: T) = { data(multidimIndices(d1,d2)) = value }
	@inline
	final def update(d1: Int, d2: Int, d3: Int, value: T) = { data(multidimIndices(d1,d2,d3)) = value }
*/
	// apply/update(seq...)
	// apply/update(range...)
}

final class FloatMatrix(paramSize: Int*)
{
	val size = paramSize.toList
	val length = size.foldLeft(1)(_*_) 
	@inline
	final val data = new Array[Float](length)
	val multidimIndices = new org.pi.common.matrix.indices.DefaultMultidimensionalIndices(size)

	@inline
	final def apply(d1: Int) : Float = data(d1)
/*	@inline
	final def apply(d1: Int, d2: Int) : T = data(multidimIndices(d1,d2))
	@inline
	final def apply(d1: Int, d2: Int, d3: Int) : T = data(multidimIndices(d1,d2,d3))
*/
	@inline
	final def update(d1: Int, value: Float) = { data(d1) = value }
/*	@inline
	final def update(d1: Int, d2: Int, value: T) = { data(multidimIndices(d1,d2)) = value }
	@inline
	final def update(d1: Int, d2: Int, d3: Int, value: T) = { data(multidimIndices(d1,d2,d3)) = value }
*/
	// apply/update(seq...)
	// apply/update(range...)
}

trait SubMatrix {
	
}

class IndexedSubMatrix extends SubMatrix {
	
}

object MatrixDesignTests {
	def main(args: Array[String]): Unit = {
		val w = 5000;
		val h = 3000;
		for (i <- 0 until 10)
		{
			for (i <- 0 until 5)
			{
				val A = new Array[Float](h*w)
				printlnTicToc("matrix test (array, while)") {
					var value: Float = 3.1f;
					var i: Int = 0;
					val n = w*h;
					while(i < n) {
						A(i) = value
						value = value + 0.7f;
						i+=1
					}
				}
			}
			for (i <- 0 until 5)
			{
				val A = new Matrix[Float](h,w)
				printlnTicToc("matrix test (investigated generic implementation, while)") {
					var value: Float = 3.1f;
					var i: Int = 0;
					val n = w*h;
					while(i < n) {
						A(i) = value
						value = value + 0.7f;
						i += 1
					}
				}
			}
			for (i <- 0 until 5)
			{
				val A = new FloatMatrix(h,w)
				printlnTicToc("matrix test (investigated implementation, while)") {
					var value: Float = 3.1f;
					var i: Int = 0;
					val n = w*h;
					while(i < n) {
						A(i) = value
						value = value + 0.7f;
						i += 1
					}
				}
			}
			for (i <- 0 until 5)
			{
				val A = new FloatMatrix(h,w)
				printlnTicToc("matrix test (indirected array, while)") {
					var value: Float = 3.1f;
					var i: Int = 0;
					val n = w*h;
					while(i < n) {
						A.data(i) = value
						value = value + 0.7f;
						i += 1
					}
				}
			}
			for (i <- 0 until 5)
			{
				val A = new FloatMatrix(h,w)
				val array = A.data;
				printlnTicToc("matrix test (indirected array with copied array reference, while)") {
					var value: Float = 3.1f;
					var i: Int = 0;
					val n = w*h;
					while(i < n) {
						array(i) = value
						value = value + 0.7f;
						i += 1
					}
				}
			}
			for (i <- 0 until 5)
			{
				val A = new org.pi.common.matrix.FloatMatrix(h,w)
				printlnTicToc("matrix test (implementation in use, while)") {
					var value: Float = 3.1f;
					var i: Int = 0;
					val n = w*h;
					while(i < n) {
						A(i) = value
						value = value + 0.7f;
						i += 1
					}
				}
			}
//			{
//				val A = new org.pi.common.matrix.Matrix[Float](h,w)
//				printlnTicToc("matrix test (org.pi.common.matrix, while)") {
//					var value: Float = 3.1f;
//					var i: Int = 0;
//					val n = w*h;
//					while(i < n) {
//						A(i) = value
//						value = value + 0.7f;
//						i += 1
//					}
//				}
//			}
		}
		println("ende.")
	}
}
